package com.ryder.subject.infra.config;

import com.alibaba.fastjson2.JSON;
import com.ryder.subject.common.util.LoginUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.*;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.*;

/**
 * 描述: 填充 created_by, created_time, updated_by, updated_time 字段
 *
 * @author Ryder
 * @version 1.0
 * @since 1.0 // 版本号，指明从哪个版本开始
 * 更新日期: 2025/03/14
 */
@Component
@Slf4j
@Intercepts({
        @Signature(type = Executor.class, method = "update", args = {
                MappedStatement.class, Object.class
        })
})
public class MybatisInterceptor implements Interceptor {

    /**
     * 拦截器
     */
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
        SqlCommandType sqlCommandType = mappedStatement.getSqlCommandType();
        Object parameter = invocation.getArgs()[1];
        if (parameter == null) {
            //如果参数为空，直接放行
            return invocation.proceed();
        }
        //获取当前登录用户id
        String loginId = LoginUtil.getLoginId();
        if (StringUtils.isBlank(loginId)) {
            //如果参数为空，直接放行
            return invocation.proceed();
        }
        //如果是insert和update，进行逻辑处理
        if (SqlCommandType.INSERT == sqlCommandType || SqlCommandType.UPDATE == sqlCommandType) {
            replaceEntityPropertry(parameter, loginId, sqlCommandType);
        }

        //正常情况放行
        return invocation.proceed();
    }

    /**
     * 拦截后的对象替换方法
     *
     * @param parameter      对象
     * @param loginId        用户id
     * @param sqlCommandType sql类型
     */
    private void replaceEntityPropertry(Object parameter, String loginId, SqlCommandType sqlCommandType) {
        if (parameter instanceof Map) {
            replaceMap((Map) parameter, loginId, sqlCommandType);
        }
        replace(parameter, loginId, sqlCommandType);
    }

    /**
     * 处理map逻辑
     *
     * @param parameter 对象
     * @param loginId   用户id
     * @param sqlCommandType sql类型
     */
    private void replaceMap(Map parameter, String loginId, SqlCommandType sqlCommandType) {
//        for (Object val : parameter.values()) {
//            replace(val, loginId, sqlCommandType);
//        }
        for (Object value : parameter.values()) {
            if (value instanceof Collection) {
                ((Collection<?>) value).forEach(v -> replace(v, loginId, sqlCommandType));
            } else {
                replace(value, loginId, sqlCommandType);
            }
        }
    }

    private void replace(Object parameter, String loginId, SqlCommandType sqlCommandType) {
        if (SqlCommandType.INSERT == sqlCommandType) {
            dealInsert(parameter, loginId);
        } else {
            dealUpdate(parameter, loginId);
        }
    }

    /**
     * 处理更新逻辑
     *
     * @param parameter 对象
     * @param loginId   用户id
     */
    private void dealUpdate(Object parameter, String loginId) {
        Field[] fields = getAllFields(parameter);
        log.info("MybatisInterceptor.dealUpdate.allFields:{}", JSON.toJSONString(fields));
        for (Field field : fields) {
            try {
                // 跳过 static 和 final 字段
                // if (Modifier.isStatic(field.getModifiers()) || Modifier.isFinal(field.getModifiers())) {
                //     continue;
                // }
                // **如果是 Map，直接跳过，不处理**
                if (parameter instanceof Map) {
                    return;
                }

                //设置可以访问和校验
                field.setAccessible(true);
                Object o = field.get(parameter);
                if (Objects.nonNull(o)) {
                    //如果不为空就不用管，设置为false
                    field.setAccessible(false);
                    continue;
                }
                // 赋默认值
                switch (field.getName()) {
                    case "updateBy":
                        field.set(parameter, loginId);
                        break;
                    case "updateTime":
                        field.set(parameter, new Date());
                        break;
                }
                field.setAccessible(false);
            } catch (Exception e) {
                log.error("MybatisInterceptor.dealUpdate.error:{}", e.getMessage(), e);
            }
        }
    }

    /**
     * 处理插入逻辑
     *
     * @param parameter 对象
     * @param loginId   用户id
     */
    private void dealInsert(Object parameter, String loginId) {
        Field[] fields = getAllFields(parameter);
        log.info("MybatisInterceptor.dealInsert.allFields:{}", JSON.toJSONString(fields));
        for (Field field : fields) {
            try {
                // 跳过 static 和 final 字段
                // if (Modifier.isStatic(field.getModifiers()) || Modifier.isFinal(field.getModifiers())) {
                //     continue;
                // }
                // **如果是 Map，直接跳过，不处理**
                if (parameter instanceof Map) {
                    return;
                }

                //设置可以访问和校验
                field.setAccessible(true);
                Object o = field.get(parameter);
                if (Objects.nonNull(o)) {
                    //如果不为空就不用管，设置为false
                    field.setAccessible(false);
                    continue;
                }
                // 赋默认值
                switch (field.getName()) {
                    case "isDeleted":
                        field.set(parameter, 0);
                        break;
                    case "createdBy":
                        field.set(parameter, loginId);
                        break;
                    case "createdTime":
                        field.set(parameter, new Date());
                        break;
                }
                field.setAccessible(false);
            } catch (Exception e) {
                log.error("MybatisInterceptor.dealInsert.error:{}", e.getMessage(), e);
            }
        }
    }

    /**
     * 获取对象的所有字段（包括继承自父类的字段）。
     *
     * @param object 目标对象，不能为 {@code null}。
     * @return 包含对象所有字段的 {@link Field} 数组。
     * @throws IllegalArgumentException 如果传入的对象为 {@code null}。
     */
    private Field[] getAllFields(Object object) {
        //参数校验
        if (object == null) {
            throw new IllegalArgumentException("目标对象不能为 null");
        }
        //获取对象的运行时类
        Class<?> clazz = object.getClass();
        //创建一个用于存储所有字段的数组
        List<Field> fieldList = new ArrayList<>();
        //递归遍历类及其所有父类，直到到达 Object 父类为止
        while (clazz != null) {
            //获取当前类中声明的所有字段（包括私有字段）
            fieldList.addAll(new ArrayList<>(Arrays.asList(clazz.getDeclaredFields())));
            //获取当前类的父类
            clazz = clazz.getSuperclass();
        }
        Field[] fields = new Field[fieldList.size()];
        fieldList.toArray(fields);
        return fields;
    }


    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {
    }
}
